#ifndef KAEP_KAEV1_MEM_H
#define KAEP_KAEV1_MEM_H

#include <semaphore.h>
#include <wd.h>
#include <wd_bmm.h>

#include <pthread.h>

#define RSA_BLOCK_NUM  16
#define RSA_BLOCK_SIZE 4096

#define DH_BLOCK_NUM  16
#define DH_BLOCK_SIZE 4096

#define CIPHER_BLOCK_NUM  4
#define CIPHER_BLOCK_SIZE (272 * 1024)

#define DIGEST_BLOCK_NUM  8
#define DIGEST_BLOCK_SIZE (512 * 1024)

struct wd_queue_mempool {
    struct wd_queue *q;
    void *base;
    unsigned int *bitmap;
    unsigned int block_size;
    unsigned int block_num;
    unsigned int mem_size;
    unsigned int block_align_size;
    unsigned int free_num;
    unsigned int fail_times;
    unsigned long long index;
    sem_t mempool_sem;
    int dev;
};

struct wd_queue *WD_NewQueue(int algType);

void WD_FreeQueue(struct wd_queue *queue);

typedef struct {
    struct wd_queue *queue;
    struct wd_queue_mempool *mempool;
    void *ctx;
} KaeQueueDataEntry;

struct KaeSpinLock {
    int lock;
};

static inline void KaeSpinLockInit(struct KaeSpinLock *lock)
{
    lock->lock = 0;
}

static inline void KaeSpinLockLock(struct KaeSpinLock *lock)
{
    while (__sync_lock_test_and_set(&lock->lock, 1)) {
    }
}

static inline int KaeSpinLockTrylock(struct KaeSpinLock *lock)
{
    return __sync_lock_test_and_set(&lock->lock, 1) == 0;
}

static inline void KaeSpinLockUnlock(struct KaeSpinLock *lock)
{
    __sync_lock_release(&lock->lock);
}

typedef struct KaeQueuePoolNode {
    struct KaeSpinLock spinlock;
    time_t addTime;
    KaeQueueDataEntry *entry;
} KaeQueuePoolNode;

typedef struct KaeQueuePoolHead {
    // int init_flag;
    int poolUseNum;
    int algType; /* alg type,just init at init pool */
    pthread_mutex_t destroyMutex;
    pthread_mutex_t kaeQueueMutex;
    struct KaeQueuePoolHead *next; /* next pool */
    KaeQueuePoolNode *kaeQueuePool; /* point to a attray */
} KaeQueuePoolHead;

KaeQueuePoolHead *KaeInitQueuePool(int algType);

KaeQueueDataEntry *KaeGetNodeFromPool(KaeQueuePoolHead *poolHead);

int KaePutNodeToPool(KaeQueuePoolHead *poolHead, KaeQueueDataEntry *nodeData);

void KaeQueuePoolReset(KaeQueuePoolHead *poolHead);

void KaeQueuePoolDestroy(KaeQueuePoolHead *poolHead);

void KaeQueuePoolCheckAndRelease(KaeQueuePoolHead *poolHead);

#endif